using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using System.Collections.ObjectModel;
using Confusing.Collections;
using Confusing.Collections.Exceptions;

namespace unittest.Confusing.Collections
{
    [TestFixture]
    public class TestCollectionHelper
    {
        [Test]
        public void TestConstructMap()
        {
            IList<MapObject> list = new List<MapObject>();
            int numObjects = 10;
            for (int i = 0; i < numObjects; i++)
            {
                list.Add(new MapObject());
            }

            Assert.IsNotNull(list);
            Assert.AreEqual(numObjects, list.Count);

            IDictionary<Guid, MapObject> map = CollectionHelper.ConstructMapFor<Guid, MapObject>(list, "Id");
            Assert.IsNotNull(map);
            Assert.AreEqual(numObjects, map.Count);
            foreach (MapObject mapObj in list)
            {
                Assert.IsNotNull(mapObj);
                Assert.IsTrue(map.ContainsKey(mapObj.Id));
                MapObject other = map[mapObj.Id];
                Assert.IsNotNull(other);
                Assert.AreEqual(mapObj, other);
            }
        }

        [NUnit.Framework.Test]
        public void TestFindInCollectionByProperty()
        {
            string methodName = new System.Diagnostics.StackFrame().GetMethod().Name;
            IList<MapObject> list = new List<MapObject>();
            int numObjects = 10;
            int indexToFind = 5;
            Assert.IsTrue(indexToFind < numObjects);
            for (int i = 0; i < numObjects; i++)
            {
                list.Add(new MapObject());
            }

            string idToFind = list[indexToFind].SomeString;

            MapObject foundObject = CollectionHelper.FindInCollectionByProperty<MapObject, IList<MapObject>, string>(list, idToFind, "SomeString", string.Compare);
            Assert.IsNotNull(foundObject);
            Assert.AreEqual(list[indexToFind], foundObject);
        }
        [NUnit.Framework.Test]
        public void TestFindInCollectionByPropertyGuid()
        {
            string methodName = new System.Diagnostics.StackFrame().GetMethod().Name;
            IList<MapObject> list = new List<MapObject>();
            int numObjects = 10;
            int indexToFind = 5;
            Assert.IsTrue(indexToFind < numObjects);

            for (int i = 0; i < numObjects; i++)
            {
                list.Add(new MapObject());
            }

            Guid idToFind = list[indexToFind].Id;

            CollectionHelper.Compare<Guid> guidComparer = new CollectionHelper.Compare<Guid>(CompareGuid);
            MapObject foundObject = CollectionHelper.FindInCollectionByProperty<MapObject, IList<MapObject>, Guid>(list, idToFind, "Id", CompareGuid);

            Assert.IsNotNull(foundObject);
            Assert.AreEqual(list[indexToFind], foundObject);
        }
        [NUnit.Framework.Test]
        public void TestFindInCollectionByPropertyInt()
        {
            string methodName = new System.Diagnostics.StackFrame().GetMethod().Name;
            IList<MapObject> list = new List<MapObject>();
            int numObjects = 10;
            int indexToFind = 5;
            Assert.IsTrue(indexToFind < numObjects);

            for (int i = 0; i < numObjects; i++)
            {
                list.Add(new MapObject());
            }

            int intToFind = list[indexToFind].SomeNum;

            CollectionHelper.Compare<Guid> guidComparer = new CollectionHelper.Compare<Guid>(CompareGuid);
            MapObject foundObject = CollectionHelper.FindInCollectionByProperty<MapObject, IList<MapObject>, int>(list, intToFind, "SomeNum", CompareInt);

            Assert.IsNotNull(foundObject);
            Assert.AreEqual(list[indexToFind], foundObject);
        }
        [NUnit.Framework.Test]
        public void TestConvertCollection()
        {
            string methodName = new System.Diagnostics.StackFrame().GetMethod().Name;
            int numElement = 10;
            Assert.IsTrue(numElement > 0);

            Collection<Guid> listSource = new Collection<Guid>();
            for (int i = 0; i < numElement; i++)
            {
                listSource.Add(Guid.NewGuid());
            }

            IList<Guid> result = CollectionHelper.ConvertCollection<Guid, ICollection<Guid>, IList<Guid>, List<Guid>>(listSource);

            for (int i = 0; i < numElement; i++)
            {
                Guid sourceId = listSource[i];
                Guid destId = result[i];
                Assert.AreEqual(sourceId, destId);
            }
        }
        [NUnit.Framework.Test]
        public void TestChangeCollectionParamType()
        {
            string methodName = new System.Diagnostics.StackFrame().GetMethod().Name;

            int numElement = 10;
            Assert.IsTrue(numElement > 0);

            IList<IMyInt1> list = new List<IMyInt1>();
            for (int i = 0; i < numElement; i++)
            {
                list.Add(new MyInt1());
            }

            IList<IMyName> result = CollectionHelper.ChangeCollectionParamType<IMyInt1, IMyName, IList<IMyInt1>, IList<IMyName>, List<IMyName>>(list);
            Assert.IsNotNull(result);
            for (int i = 0; i < numElement; i++)
            {
                MyInt1 sourceObj = (MyInt1)list[i];
                MyInt1 destObj = (MyInt1)result[i];
                Assert.AreEqual(sourceObj, destObj);
            }
        }
        [Test]
        public void TestMerge1()
        {
            //IList<int>
            IList<string> listOne = new List<string>();
            IList<string> listTwo = new List<string>();

            int numElementsInEach = 10;
            for (int i = 0; i < numElementsInEach; i++)
            {
                listOne.Add(Guid.NewGuid().ToString());
                listTwo.Add(Guid.NewGuid().ToString());
            }

            IList<string> result = CollectionHelper.MergeCollections<IList<string>, List<string>, string>(listOne, listTwo);
            Assert.IsNotNull(result);
            Assert.AreEqual(listOne.Count + listTwo.Count, result.Count);
        }
        [Test]
        public void TestMerge2()
        {
            //IList<int>
            IList<Guid> listOne = new List<Guid>();
            IList<Guid> listTwo = new List<Guid>();

            int numElementsInEach = 10;
            for (int i = 0; i < numElementsInEach; i++)
            {
                listOne.Add(Guid.NewGuid());
                listTwo.Add(Guid.NewGuid());
            }

            IList<Guid> result = CollectionHelper.MergeCollections<IList<Guid>, List<Guid>, Guid>(listOne, listTwo);
            Assert.IsNotNull(result);
            Assert.AreEqual(listOne.Count + listTwo.Count, result.Count);
        }
        #region Expected failures
        [NUnit.Framework.Test]
        [ExpectedException(typeof(UnexpectedTypeException))]
        public void ExpectedFailure01()
        {
            string methodName = new System.Diagnostics.StackFrame().GetMethod().Name;
            IList<MapObject> list = new List<MapObject>();
            int numObjects = 10;
            for (int i = 0; i < numObjects; i++)
            {
                list.Add(new MapObject());
            }

            Assert.IsNotNull(list);
            Assert.AreEqual(numObjects, list.Count);

            IDictionary<int, MapObject> map = CollectionHelper.ConstructMapFor<int, MapObject>(list, "Id");

        }
        [NUnit.Framework.Test]
        [ExpectedException(typeof(PropertyNotFoundException))]
        public void ExpectedFailurePropertyNotFound()
        {
            string methodName = new System.Diagnostics.StackFrame().GetMethod().Name;
            IList<MapObject> list = new List<MapObject>();
            int numObjects = 10;
            for (int i = 0; i < numObjects; i++)
            {
                list.Add(new MapObject());
            }

            Assert.IsNotNull(list);
            Assert.AreEqual(numObjects, list.Count);

            IDictionary<int, MapObject> map = CollectionHelper.ConstructMapFor<int, MapObject>(list, "NonExistentProperty");
        }
        [NUnit.Framework.Test]
        [ExpectedException(typeof(PropertyNotFoundException))]
        public void ExpectedFailurePropertyAccess()
        {
            string methodName = new System.Diagnostics.StackFrame().GetMethod().Name;
            IList<MapObject> list = new List<MapObject>();
            int numObjects = 10;
            for (int i = 0; i < numObjects; i++)
            {
                list.Add(new MapObject());
            }

            Assert.IsNotNull(list);
            Assert.AreEqual(numObjects, list.Count);

            IDictionary<int, MapObject> map = CollectionHelper.ConstructMapFor<int, MapObject>(list, "PrivateProperty");
        }
        #endregion

        #region Non-test cases
        public int CompareGuid(Guid one, Guid two)
        {
            return one.ToString().CompareTo(two.ToString());
        }
        public int CompareInt(int one, int two)
        {
            return one.ToString().CompareTo(two.ToString());
        }
        class MapObject
        {
            private static int NextSomeNum = 0;
            private static object NextSomeNumeLock = "NextSomeNumeLock";

            private Guid mId;
            private DateTime mCreated;
            private string mSomeString;
            private int mSomeNum;

            public MapObject()
            {
                mId = Guid.NewGuid();
                mCreated = DateTime.Now;
                mSomeString = mId.ToString();
                lock (NextSomeNumeLock)
                {
                    NextSomeNum++;
                }
                mSomeNum = NextSomeNum;
            }
            public Guid Id
            {
                get { return mId; }
                set { mId = value; }
            }
            public DateTime Created
            {
                get { return this.mCreated; }
                set { this.mCreated = value; }
            }
            public string SomeString
            {
                get { return this.mSomeString; }
                set { this.mSomeString = value; }
            }
            public int SomeNum
            {
                get { return this.mSomeNum; }
                set { this.mSomeNum = value; }
            }
            private string PrivateProperty
            {
                get { return "ThisIsATest"; }
            }
            public override bool Equals(object obj)
            {
                MapObject other = obj as MapObject;
                if (other == null)
                    return false;

                if (this.Id.Equals(other.Id) &&
                    this.Created.Equals(other.Created))
                {
                    return true;
                }

                return false;
            }
            public override int GetHashCode()
            {
                return Id.GetHashCode() + Created.GetHashCode();
            }
        }
        interface IMyInt1
        {
            Guid MyId { get;}
        }
        interface IMyName // : IMyInt1
        {
            string Name { get;}
        }
        class MyInt1 : IMyInt1, IMyName
        {
            private Guid mMyId;
            private string mName;
            public MyInt1()
            {
                mMyId = Guid.NewGuid();
                mName = mMyId.ToString();
            }

            public Guid MyId
            {
                get { return mMyId; }
                set { mMyId = value; }
            }
            public string Name
            {
                get { return this.mName; }
            }
        }
        #endregion
    }
}
